package com.jingdianjichi.subject.domain.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jingdianjichi.subject.common.entity.PageResult;
import com.jingdianjichi.subject.common.enums.IsDeletedFlagEnum;
import com.jingdianjichi.subject.common.enums.SubjectLikedStatusEnum;
import com.jingdianjichi.subject.common.utils.LoginUtil;
import com.jingdianjichi.subject.domain.convert.SubjectLikedConverter;
import com.jingdianjichi.subject.domain.entity.SubjectLikedBO;
import com.jingdianjichi.subject.domain.entity.mq.SubjectLikedMessage;
import com.jingdianjichi.subject.domain.redis.RedisUtil;
import com.jingdianjichi.subject.domain.service.SubjectLikedDomainService;
import com.jingdianjichi.subject.infra.basic.entity.SubjectInfo;
import com.jingdianjichi.subject.infra.basic.entity.SubjectLiked;
import com.jingdianjichi.subject.infra.basic.service.SubjectInfoService;
import com.jingdianjichi.subject.infra.basic.service.SubjectLikedService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Service
@Slf4j
public class SubjectLikedDomainServiceImpl implements SubjectLikedDomainService {

    @Resource
    private SubjectLikedService likedService;

    @Resource
    private SubjectInfoService infoService;

    @Resource
    private RedisUtil redisUtil;

    //这个就是hash的大key来的,因为要对点赞的行为作出记录的亲
    private static final String SUBJECT_LIKED_KEY="subject.liked";

    //题目点赞的数量,这个我们的redis数据结构就选择简单的键值对即可
    private static final String SUBJECT_LIKED_COUNT_KEY="subject.liked.count";

    //题目被谁点赞了,我们这里也是使用简答的键值对来
    private static final String SUBJECT_LIKED_DETAIL_KEY="subject.liked.detail";


    @Resource
    private RocketMQTemplate rocketMQTemplate;

    //和缓存做交互亲
    @Override
    public void add(SubjectLikedBO subjectLikedBO) {
        Long subjectId = subjectLikedBO.getSubjectId();
        String userId = subjectLikedBO.getLikeUserId();
        Integer status = subjectLikedBO.getStatus();

        //这个就是hash中的小key
        String hashKey = buildSubjectLikedKey(String.valueOf(subjectId), userId);

        //存入题目点赞的状态,就是那个题目被点赞了
        redisUtil.pushHash(SUBJECT_LIKED_KEY,hashKey,status);           //存到Redis,有题目的信息Id和点赞人的id和题目点赞的状态

        //题目被点赞的数量
        String countKey=SUBJECT_LIKED_COUNT_KEY+"."+subjectId;

        //题目被谁被谁点赞了
        String detailKey = SUBJECT_LIKED_DETAIL_KEY + "." + subjectId + "." + userId;

        //看看是点赞还是取消点赞,从而决定是+还是-count
        if (SubjectLikedStatusEnum.LIKED.getCode() == status){
            //当前就是点赞
            redisUtil.increment(countKey,1);        //这时就+1了
            redisUtil.set(detailKey,"1");                 //有这个记录就表示用户点赞成功了
        }else {
            //不能-到负数
            Integer count = redisUtil.getInt(countKey);

            //不做处理
            if (Objects.isNull(count) || count < 0){
                return;
            }

            redisUtil.increment(countKey,-1);
            redisUtil.del(detailKey);                   //用户如果取消点赞了就删除这个key就行了
        }
    }

    //这里就是使用mq实现了,我们这里和消息做交互,不用和redis做交互了,点赞数量的统计我们还是使用redis
    @Override
    public void add_plus(SubjectLikedBO subjectLikedBO) {
        Long subjectId = subjectLikedBO.getSubjectId();
        String userId = subjectLikedBO.getLikeUserId();
        Integer status = subjectLikedBO.getStatus();

        //消息实体
        SubjectLikedMessage message = new SubjectLikedMessage();
        message.setSubjectId(subjectLikedBO.getSubjectId());
        message.setLikeUserId(subjectLikedBO.getLikeUserId());
        message.setStatus(subjectLikedBO.getStatus());

        //发送mq,定义话题并且,把消息序列化
        rocketMQTemplate.convertAndSend("subject-liked",JSON.toJSONString(message));

        //题目被点赞的数量
        String countKey=SUBJECT_LIKED_COUNT_KEY+"."+subjectId;

        //题目被谁被谁点赞了
        String detailKey = SUBJECT_LIKED_DETAIL_KEY + "." + subjectId + "." + userId;

        //看看是点赞还是取消点赞,从而决定是+还是-count
        if (SubjectLikedStatusEnum.LIKED.getCode() == status){
            //当前就是点赞
            redisUtil.increment(countKey,1);        //这时就+1了
            redisUtil.set(detailKey,"1");                 //有这个记录就表示用户点赞成功了
        }else {
            //不能-到负数
            Integer count = redisUtil.getInt(countKey);

            //不做处理
            if (Objects.isNull(count) || count < 0){
                return;
            }

            redisUtil.increment(countKey,-1);
            redisUtil.del(detailKey);                   //用户如果取消点赞了就删除这个key就行了
        }
    }

    //构建hash小key
    private String buildSubjectLikedKey(String subjectId,String userId){
        return subjectId+":"+userId;
    }


    //是否被当前用户点赞
    @Override
    public Boolean isLiked(String subjectId, String userId) {
        //题目被谁被谁点赞了
        String detailKey = SUBJECT_LIKED_DETAIL_KEY + "." + subjectId + "." + userId;

        //存在就是被这个用户点赞了
        boolean exist = redisUtil.exist(detailKey);

        return exist;
    }

    //获得当前题目的点赞总数
    @Override
    public Integer getLikedCount(String subjectId) {
        //题目被点赞的数量
        String countKey=SUBJECT_LIKED_COUNT_KEY+"."+subjectId;
        Integer count = redisUtil.getInt(countKey);             //被点赞的数量

        //非空判断
        if (Objects.isNull(count) || count==0){
            return 0;
        }

        return count;
    }

    /**
     * 批量插入数据库中亲
     */
    @Override
    public void syncLiked() {
        Map<Object,Object> subjectLikedMap=redisUtil.getHashAndDelete(SUBJECT_LIKED_KEY);

        //向数据库中批量插入数据亲
        if (log.isInfoEnabled()){
            log.info("syncLiked.subjectLikedMap:{}", JSON.toJSONString(subjectLikedMap));
        }

        if (MapUtils.isEmpty(subjectLikedMap)){
            return;
        }

        //我们转为list传过去
        List<SubjectLiked> subjectLikedList=new ArrayList<>();

        subjectLikedMap.forEach((key,value)->{
            SubjectLiked subjectLiked = new SubjectLiked();
            String[] keyArr = key.toString().split(":");

            //约定来的亲,我们就是这样穿的键
            String subjectId = keyArr[0];
            String likedUser = keyArr[1];

            subjectLiked.setSubjectId(Long.valueOf(subjectId));
            subjectLiked.setLikeUserId(likedUser);
            subjectLiked.setStatus((Integer) value);
            subjectLiked.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

            subjectLikedList.add(subjectLiked);
        });

        likedService.batchInsert(subjectLikedList);     //批量插入亲
    }

    //获得我的点赞列表
    @Override
    public PageResult<SubjectLikedBO> getSubjectLikePage(SubjectLikedBO subjectLikedBO) {
        PageResult<SubjectLikedBO> pageResult = new PageResult<>();

        //设置分页参数
        pageResult.setPageNo(subjectLikedBO.getPageNo());
        pageResult.setPageSize(subjectLikedBO.getPageSize());
        int start = (subjectLikedBO.getPageNo() - 1) * subjectLikedBO.getPageSize();

        SubjectLiked subjectLiked=SubjectLikedConverter.INSTANCE.convertBOtoEntity(subjectLikedBO);
        subjectLiked.setLikeUserId(LoginUtil.getLoginId());     //封装用户亲

        //统计总数
        int count=likedService.countByCondition(subjectLiked);

        if (count == 0) {
            return pageResult;
        }
        List<SubjectLiked> subjectLikedList = likedService.queryPage(subjectLiked, start,subjectLikedBO.getPageSize());

        //我的点赞的去哪不数据亲
        List<SubjectLikedBO> subjectInfoBOS = SubjectLikedConverter.INSTANCE.convertListInfoToBO(subjectLikedList);

        subjectInfoBOS.forEach(info -> {
            SubjectInfo subjectInfo = infoService.queryById(info.getSubjectId());       //人家要的是题目的名称,我们在查一下把名称插出来
            info.setSubjectName(subjectInfo.getSubjectName());
        });

        pageResult.setRecords(subjectInfoBOS);
        pageResult.setTotal(count);

        return pageResult;
    }


    //同步mq消息到数据库,因为我们不是redis的哈希结构消息是一个一个接受的,你可以不使用集合的
    @Override
    public void syncLikedByMessage(SubjectLikedBO subjectLikedBO) {
        List<SubjectLiked> list=new ArrayList<>();

        SubjectLiked subjectLiked = new SubjectLiked();
        subjectLiked.setSubjectId(subjectLikedBO.getSubjectId());
        subjectLiked.setLikeUserId(subjectLikedBO.getLikeUserId());
        subjectLiked.setStatus(subjectLikedBO.getStatus());
        subjectLiked.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        list.add(subjectLiked);

        likedService.batchInsert(list);
    }
}
